package org.scala.javafx.diagnostics

import javafx.animation.Timeline
import javafx.animation.KeyFrame
import javafx.animation.KeyValue
import javafx.beans.value.WritableValue
import javafx.event.EventHandler
import javafx.event.ActionEvent
import javafx.scene.input.MouseEvent
import javafx.scene.shape.Rectangle
import javafx.scene.Scene
import javafx.util.Duration
import org.scala.javafx.rich.Enrich._
import org.scala.javafx.geometry.Bounds2D
import javafx.animation.Interpolator

import scala.collection.JavaConverters._

class SpyRectangle extends Rectangle {
  var timeline = new Timeline()
  var spyScopeGlass: SpyScopeGlass = null
  this.setStyle(
      "-fx-fill: rgb(0%,100%,0%,0.1);" +
      "-fx-stroke: green;" +
      "-fx-stroke-width: 2;" +
      "-fx-stroke-line-cap: butt;" +
      "-fx-effect: dropshadow(gaussian, black, 5.0, 0.1, 3.0, 3.0);")
      
  def forwardMouseEventsTo(scene: Scene): Unit = {
    this.setOnMousePressed { mouseEvent: MouseEvent =>
      scene.impl_processMouseEvent(mouseEvent)
    }
    this.setOnMouseReleased { mouseEvent: MouseEvent =>
      scene.impl_processMouseEvent(mouseEvent)
    }
  }
  
  def appear(spyScopeGlass: SpyScopeGlass, target: Bounds2D): Unit = {
    val timeline = new Timeline()
    var source = target.inflate(5.0)
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.ZERO,
            new KeyValue(this.layoutXProperty(): WritableValue[Number], source.minX: Number),
            new KeyValue(this.layoutYProperty(): WritableValue[Number], source.minY: Number),
            new KeyValue(this.widthProperty(): WritableValue[Number], source.width: Number),
            new KeyValue(this.heightProperty(): WritableValue[Number], source.height: Number)))
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.seconds(0.5),
            new KeyValue(this.layoutXProperty(): WritableValue[Number], target.minX: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.layoutYProperty(): WritableValue[Number], target.minY: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.widthProperty(): WritableValue[Number], target.width: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.heightProperty(): WritableValue[Number], target.height: Number, Interpolator.EASE_BOTH)))
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.seconds(0.5),
            new EventHandler[ActionEvent]() {
              override def handle(event: ActionEvent): Unit = {
                spyScopeGlass.screenGroup.getChildren().remove(this)
              }
            }))
    if (this.timeline != null) {
      this.timeline.jumpTo("end")
    }
    timeline.play()
    this.timeline = timeline
  }

  def disappear(spyScopeGlass: SpyScopeGlass, source: Bounds2D): Unit = {
    println("--> disapearring")
    val timeline = new Timeline()
    var target = source.inflate(5.0)
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.ZERO,
            new KeyValue(this.layoutXProperty(): WritableValue[Number], source.minX: Number),
            new KeyValue(this.layoutYProperty(): WritableValue[Number], source.minY: Number),
            new KeyValue(this.widthProperty(): WritableValue[Number], source.width: Number),
            new KeyValue(this.heightProperty(): WritableValue[Number], source.height: Number)))
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.seconds(0.5),
            new KeyValue(this.layoutXProperty(): WritableValue[Number], target.minX: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.layoutYProperty(): WritableValue[Number], target.minY: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.widthProperty(): WritableValue[Number], target.width: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.heightProperty(): WritableValue[Number], target.height: Number, Interpolator.EASE_BOTH)))
    timeline.setOnFinished(
        new EventHandler[ActionEvent]() {
          override def handle(event: ActionEvent): Unit = {
            println("--> children: " + spyScopeGlass.screenGroup.getChildren().size())
            println("--> rectangle to remove: " + this)
            for (x <- spyScopeGlass.screenGroup.getChildren().asScala) {
              println("--> x: " + x)
            }
            val result = spyScopeGlass.screenGroup.getChildren().remove(SpyRectangle.this)
            println("--> removed: " + result)
          }
        })
    if (this.timeline != null) {
      this.timeline.jumpTo("end")
    }
    timeline.play()
    this.timeline = timeline
  }
  
  def move(spyScopeGlass: SpyScopeGlass, source: Bounds2D, target: Bounds2D): Unit = {
    this.spyScopeGlass = spyScopeGlass
    if (!spyScopeGlass.isShowing()) {
      spyScopeGlass.show()
    }
    val x = spyScopeGlass.screenGroup.getChildren().addDistinct(this)
    val timeline = new Timeline()
    timeline.setCycleCount(1)
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.ZERO,
            new KeyValue(this.layoutXProperty(): WritableValue[Number], source.minX: Number),
            new KeyValue(this.layoutYProperty(): WritableValue[Number], source.minY: Number),
            new KeyValue(this.widthProperty(): WritableValue[Number], source.width: Number),
            new KeyValue(this.heightProperty(): WritableValue[Number], source.height: Number)))
    timeline.getKeyFrames().add(
        new KeyFrame(
            Duration.seconds(0.5),
            new KeyValue(this.layoutXProperty(): WritableValue[Number], target.minX: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.layoutYProperty(): WritableValue[Number], target.minY: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.widthProperty(): WritableValue[Number], target.width: Number, Interpolator.EASE_BOTH),
            new KeyValue(this.heightProperty(): WritableValue[Number], target.height: Number, Interpolator.EASE_BOTH)))
    if (this.timeline != null) {
      this.timeline.jumpTo("end")
    }
    timeline.play()
    this.timeline = timeline
  }
}
